package com.lizemin.spring;

import cn.hutool.core.annotation.AnnotationUtil;
import cn.hutool.core.util.ClassUtil;
import com.lizemin.spring.annotation.Component;
import com.lizemin.spring.annotation.SpringbootApplication;
import com.lizemin.spring.server.TomcatServer;

import java.lang.annotation.Annotation;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;

/**
 * @author lzm
 * @date 2025/4/26 12:01
 * @description 项目启动类
 */
public class SpringApplication {

    public static void run(Class<?> mainClass, String[] args) {
        SpringbootApplication springbootApplication = mainClass.getAnnotation(SpringbootApplication.class);
        if (Objects.isNull(springbootApplication)) {
            throw new RuntimeException("启动类上缺少@SpringbootApplication注解");
        }
        String[] basePackages = springbootApplication.basePackages();
        if (basePackages.length == 0) {
            String name = mainClass.getPackage().getName();
            basePackages = new String[]{name};
        }
        Set<Class<?>> beanClasses = new HashSet<>();
        for (String basePackage : basePackages) {
            // 扫描包路径下的类
            Set<Class<?>> classes = ClassUtil.scanPackage(basePackage);
            for (Class<?> clazz : classes) {
                if (clazz.isInterface()) {
                    continue;
                }
                if (clazz.isAnnotationPresent(Component.class)) {
                    beanClasses.add(clazz);
                    continue;
                }
                Annotation[] annotations = clazz.getAnnotations();
                addComponentClazz(clazz, annotations, beanClasses);
            }
        }
        BeanFactory beanFactory = new BeanFactory(beanClasses);
        beanFactory.registerBean();

        // 启动Tomcat服务器
        new TomcatServer().start();
    }

    private static void addComponentClazz(Class<?> clazz, Annotation[] annotations, Set<Class<?>> beanClasses) {
        if (annotations == null) {
            return;
        }
        // 这里要过滤掉JDK自带的元注解，否则会发生栈溢出
        annotations = Arrays.stream(annotations).filter(annotation ->
                        AnnotationUtil.isNotJdkMateAnnotation(annotation.annotationType()))
                .toArray(Annotation[]::new);
        for (Annotation annotation : annotations) {
            // 注意：这里要使用annotationType方法，如果使用getClass方法，拿到的是代理对象的class
            Class<? extends Annotation> annotationClazz = annotation.annotationType();
            if (annotationClazz.isAnnotationPresent(Component.class)) {
                beanClasses.add(clazz);
                return;
            }else {
                addComponentClazz(clazz, annotationClazz.getAnnotations(), beanClasses);
            }
        }
    }


}
